<template>
  <div class="wrapper">
    <div class="cinema-wrapper">
      <h1 class="title">电影院推荐座位</h1>
      <div class="btn-wrapper">
        <div
          class="btn-buy"
          @click="handleBuySeat"
        >
          选定座位
        </div>
        <div
          class="btn-buy"
          @click="handleReseatSeat"
        >
          重置座位
        </div>
        <template v-for="(item,index) in smartChooseMaxNum">
          <div
            :key="index"
            class="btn-buy smart"
            @click="smartChoose(index+1)"
          >
            推荐选座 {{ index+1 }} 人
          </div>
        </template>
      </div>
      <div class="seat-wrapper">
        <div class="illustration">
          <div class="illustration-img-wrapper unselected-seat" />
          <span class="illustration-text">可选</span>
          <div class="illustration-img-wrapper selected-seat" />
          <span class="illustration-text">已选</span>
          <div class="illustration-img-wrapper bought-seat" />
          <span class="illustration-text">不可选</span>
        </div>
        <div class="screen">3好激光厅银幕</div>
        <div class="screen-center">银幕中央
          <div class="mid-line" />
        </div>
        <div
          ref="innerSeatWrapper"
          class="inner-seat-wrapper"
        >
          <div v-if="seatArray.length>0">
            <div
              v-for="(row,index) in seatRow"
              :key="index"
            >
              <div
                v-for="(col,index) in seatCol"
                :key="index"
                class="seat"
                :style="{width:seatSize+'px',height:seatSize+'px'}"
              >
                <div
                  v-if="seatArray[row-1][col-1]!==-1"
                  class="inner-seat"
                  :class="seatArray[row-1][col-1]===2?'bought-seat':(seatArray[row-1][col-1]===1?'selected-seat':'unselected-seat')"
                  @click="handleChooseSeat(row-1,col-1)"
                />
              </div>
            </div>
          </div>

        </div>

      </div>
    </div>
  </div>
</template>

<script>
export default {
  data() {
    return {
      // 推荐选座最大数量
      smartChooseMaxNum: 5,
      // 影院座位列数
      seatCol: 20,
      // 座位尺寸
      seatSize: '',
      // 影院座位行数
      seatRow: 10,
      // 影院座位得二维数组，-1为非座位，0为未购座位，1为已选座位（绿色），2为已购座位（红色）
      seatArray: []
    }
  },
  mounted() {
    this.initSeatArray()
  },
  methods: {
    // 初始化位置
    initSeatArray() {
      const seatArray = Array(this.seatRow).fill(0).map(() => Array(this.seatCol).fill(0))
      this.seatArray = seatArray
      this.seatSize = this.$refs.innerSeatWrapper ? parseInt(parseInt(window.getComputedStyle(this.$refs.innerSeatWrapper).width, 10) / this.seatCol, 10) : 0
      this.initNonSeatPlace()
      console.log(this.seatArray)
    },
    // 初始化不是座位的地方
    initNonSeatPlace() {
      for (let i = 0; i < 9; i++) {
        this.seatArray[i][0] = -1
      }
      for (let i = 0; i < 8; i++) {
        this.seatArray[i][this.seatArray[0].length - 1] = -1
        this.seatArray[i][this.seatArray[0].length - 2] = -1
      }
      for (let i = 0; i < 9; i++) {
        this.seatArray[i][this.seatArray[0].length - 3] = -1
      }
      for (let i = 0; i < this.seatArray[0].length; i++) {
        this.seatArray[2][i] = -1
      }
    },
    // 选定位置
    handleBuySeat() {
      const oldArray = this.seatArray.slice()
      for (let i = 0; i < this.seatRow; i++) {
        for (let j = 0; j < this.seatCol; j++) {
          if (oldArray[i][j] === 1) {
            oldArray[i][j] = 2
          }
        }
      }
      this.seatArray = oldArray
    },
    // 向前后某个方向进行搜索得函数，参数是起始行，终止行，推荐座位个数
    searchSeatByDirection(fromRow, toRow, num) {
      /*
       * 推荐座位规则
       * (1)初始状态从座位行数的一半处的后一排的中间开始向左右分别搜索，取离中间最近的，如果满足条件，
       *    记录下该结果离座位中轴线的距离，后排搜索完成后取距离最小的那个结果座位最终结果，优先向后排进行搜索，
       *    后排都没有才往前排搜，前排逻辑同上
       *
       * (2)只考虑并排且连续的座位，不能不在一排或者一排中间有分隔
       *
       * */

      /*
       * 保存当前方向搜索结果的数组,元素是对象,result是结果数组，offset代表与中轴线的偏移距离
       * {
       *   result:Array([x,y])
       *   offset:Number
       * }
       *
       */
      const currentDirectionSearchResult = []

      const largeRow = fromRow > toRow ? fromRow : toRow; const smallRow = fromRow > toRow ? toRow : fromRow
      for (let i = smallRow; i <= largeRow; i++) {
        // 每一排搜索，招数该排里离中轴线最近的一组座位
        let tempRowResult = []
        let minDistanceToMidLine = Infinity
        for (let j = 0; j <= this.seatCol - num; j++) {
          // 如果有合法位置
          if (this.checkRowSeatContinusAndEmpty(i, j, j + num - 1)) {
            // 计算该组位置距离中轴线的距离，该组位置的中间位置到中轴线的距离
            const resultMidPos = parseInt((j + num / 2), 10)
            const distance = Math.abs(parseInt(this.seatCol / 2) - resultMidPos)
            // 如果距离较近则更新
            if (distance < minDistanceToMidLine) {
              minDistanceToMidLine = distance
              // 该行的最终结果
              tempRowResult = this.generateRowResult(i, j, j + num - 1)
            }
          }
        }
        // 保存该行的最终结果
        currentDirectionSearchResult.push({

          result: tempRowResult,
          offset: minDistanceToMidLine
        })
      }
      // 处理后排的搜索结果:找到距离中轴线最短的一个
      // 注意这里的逻辑需要区分前后排，对于后排是从前往后，前排则是从后往前找
      const isBackDir = fromRow < toRow
      let finalResult = []; let minDistanceToMid = Infinity
      if (isBackDir) {
        // 后排情况，从前往后
        currentDirectionSearchResult.forEach((item) => {
          if (item.offset < minDistanceToMid) {
            finalResult = item.result
            minDistanceToMid = item.offset
          }
        })
      } else {
        // 前排情况，从后往前找
        currentDirectionSearchResult.reverse().forEach((item) => {
          if (item.offset < minDistanceToMid) {
            finalResult = item.result
            minDistanceToMid = item.offset
          }
        })
      }
      return finalResult
    },
    // 返回每一行的某个合理位置的座位数组
    generateRowResult(row, startPos, endPos) {
      const result = []
      for (let i = startPos; i <= endPos; i++) {
        result.push([row, i])
      }
      return result
    },
    // 判断每一行座位从i列到j列是否全部空余且连续
    checkRowSeatContinusAndEmpty(rowNum, startPos, endPos) {
      let isValid = true
      for (let i = startPos; i <= endPos; i++) {
        if (this.seatArray[rowNum][i] !== 0) {
          isValid = false
          break
        }
      }
      return isValid
    },
    // 重置位置
    handleReseatSeat() {
      const oldArray = this.seatArray.slice()
      for (let i = 0; i < this.seatRow; i++) {
        for (let j = 0; j < this.seatCol; j++) {
          if (oldArray[i][j] !== -1) {
            oldArray[i][j] = 0
          }
        }
      }
      this.seatArray = oldArray
    },
    // 智能推荐的选座操作
    chooseSeat(result) {
      const oldArray = this.seatArray.slice()
      for (let i = 0; i < result.length; i++) {
        // 选定座位
        oldArray[result[i][0]][result[i][1]] = 1
      }
      this.seatArray = oldArray
    },
    // 推荐选座
    smartChoose(num) {
      // 水平垂直中间位置得后一排
      const rowStart = parseInt((this.seatRow - 1) / 2, 10) + 1
      // 先从中间排往后排搜索
      const backResult = this.searchSeatByDirection(rowStart, this.seatRow - 1, num)
      if (backResult.length > 0) {
        this.chooseSeat(backResult)
        return
      }
      // 再从中间排往前搜索
      const forwardResult = this.searchSeatByDirection(rowStart - 1, 0, num)
      if (forwardResult.length > 0) {
        this.chooseSeat(forwardResult)
        return
      }
      alert('无合法位置可选!')
    },
    // 处理座位选择逻辑
    handleChooseSeat(row, col) {
      const seatValue = this.seatArray[row][col]
      const newArray = this.seatArray
      if (seatValue === 2) return
      if (seatValue === 1) {
        newArray[row][col] = 0
      } else if (seatValue === 0) {
        newArray[row][col] = 1
      }
      this.seatArray = newArray.slice()
    }
  }
}
</script>

<style lang="scss" scoped>
.wrapper {
  height: 100%;
  padding: 40px;
  box-sizing: border-box;
  .cinema-wrapper {
    height: 100%;
    .title {
      text-align: center;
    }
    .btn-wrapper {
      margin: 20px auto;
      width: 1000px;
      height: 30px;
      text-align: center;
      .btn-buy {
        height: 100%;
        line-height: 30px;
        font-size: 14px;
        border-radius: 5px;
        padding: 0 5px;
        background-color: #ffa349;
        color: #ffffff;
        display: inline-block;
        cursor: pointer;
        margin-right: 10px;
      }
    }
  }

  .seat-wrapper {
    height: 700px;
    width: 1000px;
    border: 1px dotted #c5c5c5;
    margin: 0 auto;
    position: relative;
    overflow: hidden;
    .illustration {
      position: absolute;
      left: 0;
      top: 0;
      height: 35px;
      width: 300px;
      .illustration-img-wrapper {
        width: 25px;
        height: 25px;
        position: relative;
        top: 50%;
        display: inline-block;
        transform: translateY(-50%);
        margin-left: 10px;
      }
      .illustration-text {
        display: inline-block;
        height: 100%;
        line-height: 35px;
        font-size: 14px;
        position: relative;
        top: -2px;
      }
    }
    .screen {
      margin: 0 auto;
      height: 30px;
      width: 300px;
      background-color: #e3e3e3;
      border-radius: 0 0 30px 30px;
      color: #585858;
      line-height: 30px;
      text-align: center;
    }
    .screen-center {
      position: absolute;
      left: 50%;
      transform: translateX(-50%);
      padding: 5px;
      font-size: 13px;
      border-radius: 5px;
      top: 50px;
      background-color: #f6f6f6;
      color: #636363;
      border: 1px solid #b1b1b1;
      .mid-line {
        position: absolute;
        left: 50%;
        transform: translateX(-50%);
        top: 100%;
        width: 1px;
        height: 800px;
        border-left: 1px dashed #919191;
      }
    }
    .inner-seat-wrapper {
      position: absolute;
      top: 120px;
      bottom: 0;
      width: 100%;
      box-sizing: border-box;
      .seat {
        float: left;
        display: flex;
        justify-content: center;
        align-items: center;
        .inner-seat {
          width: 80%;
          height: 80%;
          cursor: pointer;
        }
      }
    }
  }
  .selected-seat {
    background: url("./../assets/selected.png") center center no-repeat;
    background-size: 100% 100%;
  }
  .unselected-seat {
    background: url("./../assets/unselected.png") center center no-repeat;
    background-size: 100% 100%;
  }
  .bought-seat {
    background: url("./../assets/bought.png") center center no-repeat;
    background-size: 100% 100%;
  }
}
</style>
